package xin.alum.aim.handler;

import com.google.protobuf.Any;
import com.google.protobuf.InvalidProtocolBufferException;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import xin.alum.aim.AIM;
import xin.alum.aim.config.DataAgreement;
import xin.alum.aim.constant.ChannelAttr;
import xin.alum.aim.constant.ChannelClose;
import xin.alum.aim.constant.ChannelPlatform;
import xin.alum.aim.groups.Session;
import xin.alum.aim.groups.SessionGroups;
import xin.alum.aim.groups.Sessions;
import xin.alum.aim.model.Reply;
import xin.alum.aim.model.Sent;
import xin.alum.aim.model.proto.Packet;
import xin.alum.aim.model.proto.ProtoJsonUtil;
import xin.alum.aim.util.GZipUtil;

import java.io.InputStream;
import java.util.Map;

/**
 * 此类为源码测试接受者
 * 正式业务请重写此服务类
 *
 * @auther alum(alum @ live.cn)
 * @date 2021/8/5 10:01
 */
public class AimReceiver implements AimReceive {

    /**
     * 所有会话
     */
    @Autowired
    protected Sessions sessions;

    /**
     * 所有群组
     */
    @Autowired
    protected SessionGroups groups;

    /**
     * 日志对象
     */
    protected final InternalLogger logger = InternalLoggerFactory.getInstance(this.getClass());

    /**
     * WebSocket握手处理逻辑，绑定用户信息到会话系统
     *
     * @param ch  当前连接通道
     * @param req 当前上行请求,URL参数已经放入ch中
     * @param res 握手失败 return false 输出给客户端的对象
     * @return
     */
    @Override
    public boolean onHandShake(Channel ch, FullHttpRequest req, FullHttpResponse res) {
        return true;
    }

    /**
     * Socks基于自定义Bing握手处理逻辑，绑定用户信息到会话系统
     *
     * @param ch 通道
     * @param in 握手数据包
     * @return
     */
    @Override
    public boolean onHandShake(Channel ch, ByteBuf in) {
        return true;
    }

    /**
     * Socks基于ProtoBuf-Login的握手处理逻辑
     *
     * @param ch
     * @param user
     * @param token
     * @return
     */
    @Override
    public boolean onHandShake(Channel ch, String user, String token) {
        return true;
    }

    @Override
    public void onHandShaked(Channel ch) {
        if (sessions != null) {
            sessions.bindUser(ch, ch.id().toString(), ChannelPlatform.NON, "");
        }
    }

    @Override
    public void onPing(Channel ch) {

    }

    /**
     * Text类型数据处理，测试用，正式业务请重写
     *
     * @param ch
     * @param text
     */
    @Override
    public void onText(Channel ch, String text) {
        if (ch.attr(ChannelAttr.AGREEMENT).get() == Packet.Agreement.Text) {
            ch.writeAndFlush(text);
        } else {
            text = GZipUtil.ungzip(AIM.properties.getGzip(), text);
            ProtoJsonUtil protoJsonUtil = new ProtoJsonUtil(Packet.Data.getDescriptor());
            Packet.Sent p = (Packet.Sent) protoJsonUtil.toProto(Packet.Sent.newBuilder(), text);
            onRecive(ch, new Sent(p.getKey(), p.getData()));
        }
    }


    /**
     * 处理WebSocket binary请求
     * 测试方法，正式业务请重写
     *
     * @param ch
     * @param in
     * @throws InvalidProtocolBufferException
     */
    @Override
    public void onByte(Channel ch, ByteBuf in) {
        try {
            if (ch.attr(ChannelAttr.AGREEMENT).get() == Packet.Agreement.Binary) {
                logger.error("{}{}协议未实现", ch, Packet.Agreement.Binary);
                return;
            }
            InputStream inputStream = new ByteBufInputStream(in);
            Packet.Sent m = Packet.Sent.parseFrom(inputStream);
            Sent t = new Sent(m.getKey(), m.getTimestamp(), m.getData());
            onRecive(ch, t);
        } catch (Exception e) {
            logger.error("{} 数据解析异常,{},{}", ch.id(), e.getMessage(), e);
        }
    }

    /**
     * 测试方法，正式业务请重写
     *
     * @param ch
     * @param s
     */
    @Override
    public void onRecive(Channel ch, Sent s) {
        Reply reply = new Reply(s.getKey());
        reply.setData(s.getData());
        logger.error("{}群发【{}】消息{}人", ch, sessions.name(), sessions.size());
        sessions.sends(reply);
    }

    @Override
    public Reply onKick(Channel ch, Session session) {
        logger.warn("{}用户【{}】通过{}-{}登录", ch, session.getUid(), session.getPlatform(), session.getClientIp());
        return new Reply("99", String.format("%s用户【%s】通过%s-%s登录", ch, session.getUid(), session.getPlatform(), session.getClientIp()));
    }

    @Override
    public void onClose(Channel ch, ChannelClose close) {
        logger.warn("{}因{}而关闭.", ch, close.name());
    }

}
